// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   LocalURLFetchService.java

package com.google.appengine.api.urlfetch.dev;

import com.google.appengine.repackaged.com.google.protobuf.ByteString;
import com.google.appengine.repackaged.org.apache.http.Header;
import com.google.appengine.repackaged.org.apache.http.HttpEntity;
import com.google.appengine.repackaged.org.apache.http.HttpHost;
import com.google.appengine.repackaged.org.apache.http.HttpResponse;
import com.google.appengine.repackaged.org.apache.http.client.HttpClient;
import com.google.appengine.repackaged.org.apache.http.client.methods.*;
import com.google.appengine.repackaged.org.apache.http.client.params.HttpClientParams;
import com.google.appengine.repackaged.org.apache.http.conn.params.ConnRoutePNames;
import com.google.appengine.repackaged.org.apache.http.conn.scheme.PlainSocketFactory;
import com.google.appengine.repackaged.org.apache.http.conn.scheme.Scheme;
import com.google.appengine.repackaged.org.apache.http.conn.scheme.SchemeRegistry;
import com.google.appengine.repackaged.org.apache.http.conn.ssl.SSLSocketFactory;
import com.google.appengine.repackaged.org.apache.http.entity.ByteArrayEntity;
import com.google.appengine.repackaged.org.apache.http.impl.client.DefaultHttpClient;
import com.google.appengine.repackaged.org.apache.http.impl.conn.ProxySelectorRoutePlanner;
import com.google.appengine.repackaged.org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import com.google.appengine.repackaged.org.apache.http.params.BasicHttpParams;
import com.google.appengine.repackaged.org.apache.http.params.HttpConnectionParams;
import com.google.appengine.repackaged.org.apache.http.params.HttpParams;
import com.google.appengine.repackaged.org.apache.http.protocol.BasicHttpContext;
import com.google.appengine.repackaged.org.apache.http.protocol.HttpContext;
import com.google.appengine.tools.development.AbstractLocalRpcService;
import com.google.appengine.tools.development.LocalServiceContext;

import javax.net.ssl.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.ProxySelector;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

// Referenced classes of package com.google.appengine.api.urlfetch.dev:
//            AllMethodsRedirectHandler

public class LocalURLFetchService extends AbstractLocalRpcService
{
    private static interface MethodFactory
    {

        public abstract HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest urlfetchrequest);
    }


    public LocalURLFetchService()
    {
        maxResponseLength = 0x2000000;
        maxRedirects = 5;
        logger = Logger.getLogger(LocalURLFetchService.class.getName());
        timeoutInMs = 0x927c0;
    }

    private static Map buildMethodFactoryMap()
    {
        Map map = new HashMap();
        map.put(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.GET, new MethodFactory() {

            public HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
            {
                return new HttpGet(request.getUrl());
            }

        }
);
        map.put(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.DELETE, new MethodFactory() {

            public HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
            {
                return new HttpDelete(request.getUrl());
            }

        }
);
        map.put(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.HEAD, new MethodFactory() {

            public HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
            {
                return new HttpHead(request.getUrl());
            }

        }
);
        map.put(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.POST, new MethodFactory() {

            public HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
            {
                HttpPost post = new HttpPost(request.getUrl());
                if(request.hasPayload())
                {
                    ByteArrayEntity requestEntity = new ByteArrayEntity(request.getPayload().toByteArray());
                    post.setEntity(requestEntity);
                }
                return post;
            }

        }
);
        map.put(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.PUT, new MethodFactory() {

            public HttpRequestBase buildMethod(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
            {
                HttpPut put = new HttpPut(request.getUrl());
                if(request.hasPayload())
                {
                    ByteArrayEntity requestEntity = new ByteArrayEntity(request.getPayload().toByteArray());
                    put.setEntity(requestEntity);
                }
                return put;
            }

        }
);
        return map;
    }

    public String getPackage()
    {
        return "urlfetch";
    }

    public void setTimeoutInMs(int timeoutInMs)
    {
        this.timeoutInMs = timeoutInMs;
    }

    private KeyStore getTrustStore()
        throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException
    {
        InputStream is = getClass().getResourceAsStream("/com/google/appengine/api/urlfetch/dev/cacerts");
        if(is == null)
        {
            throw new IOException("Couldn't get trust store stream");
        } else
        {
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(is, null);
            return ks;
        }
    }

    private Scheme createValidatingScheme()
        throws Exception
    {
        KeyManagerFactory kmFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmFactory.init(null, null);
        javax.net.ssl.KeyManager keyManagers[] = kmFactory.getKeyManagers();
        TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmFactory.init(getTrustStore());
        TrustManager trustManagers[] = tmFactory.getTrustManagers();
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagers, trustManagers, null);
        SSLSocketFactory strictSocketFactory = new SSLSocketFactory(sslContext);
        strictSocketFactory.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
        return new Scheme("https", strictSocketFactory, 443);
    }

    private Scheme createNonvalidatingScheme()
        throws KeyManagementException, NoSuchAlgorithmException
    {
        X509TrustManager poorLifeChoicesTrustManager = new X509TrustManager() {

            public void checkClientTrusted(X509Certificate ax509certificate[], String s)
                throws CertificateException
            {
            }

            public void checkServerTrusted(X509Certificate ax509certificate[], String s)
                throws CertificateException
            {
            }

            public X509Certificate[] getAcceptedIssuers()
            {
                return null;
            }

        }
;
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[] {
            poorLifeChoicesTrustManager
        }, null);
        return new Scheme("https", new SSLSocketFactory(sslContext), 443);
    }

    public HttpClient createHttpClient(boolean validateHttps)
    {
        Scheme urlfetchHttps = null;
        if(validateHttps)
            try
            {
                urlfetchHttps = createValidatingScheme();
            }
            catch(Exception e)
            {
                validateHttps = false;
                logger.log(Level.WARNING, "Encountered exception trying to initialize SSL. SSL certificate validation will be disabled", e);
            }
        if(!validateHttps)
            try
            {
                urlfetchHttps = createNonvalidatingScheme();
            }
            catch(KeyManagementException kme)
            {
                logger.log(Level.WARNING, "Encountered exception trying to initialize SSL. All HTTPS fetches will be disabled.", kme);
                urlfetchHttps = null;
            }
            catch(NoSuchAlgorithmException nsae)
            {
                logger.log(Level.WARNING, "Encountered exception trying to initialize SSL. All HTTPS fetches will be disabled.", nsae);
                urlfetchHttps = null;
            }
        Scheme urlfetchHttp = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
        SchemeRegistry sr = new SchemeRegistry();
        if(urlfetchHttps != null)
            sr.register(urlfetchHttps);
        sr.register(urlfetchHttp);
        DefaultHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(new BasicHttpParams(), sr), new BasicHttpParams());
        client.getParams().setIntParameter("http.protocol.max-redirects", maxRedirects);
        client.setRedirectHandler(new AllMethodsRedirectHandler());
        ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(client.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
        client.setRoutePlanner(routePlanner);

        // --- todo proxy settings
        HttpHost proxy = new HttpHost("10.140.192.81", 8080, "http");
        System.out.println("Using proxy: " + proxy);
        client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
        // -----------------------

        return client;
    }

    public void init(LocalServiceContext context, Map properties)
    {
        validatingClient = createHttpClient(true);
        nonValidatingClient = createHttpClient(false);
    }

    public void start()
    {
    }

    public void stop()
    {
    }

    private byte[] responseToByteArray(HttpEntity responseEntity)
        throws IOException
    {
        InputStream responseInputStream = responseEntity.getContent();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte tempBuffer[] = new byte[4096];
        long total = 0L;
        do
        {
            int result = responseInputStream.read(tempBuffer);
            if(result != -1)
            {
                baos.write(tempBuffer, 0, result);
                total += result;
            } else
            {
                return baos.toByteArray();
            }
        } while(true);
    }

    public com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse fetch(com.google.appengine.tools.development.LocalRpcService.Status status, com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
    {
        if(status == null)
            throw new NullPointerException("status cannot be null.");
        if(request == null)
            throw new NullPointerException("request cannot be null.");
        if(!hasValidURL(request))
            throw new com.google.apphosting.api.ApiProxy.ApplicationException(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchServiceError.ErrorCode.INVALID_URL.getNumber(), (new StringBuilder()).append("Invalid URL: ").append(request.getUrl()).toString());
        MethodFactory methodFactory = (MethodFactory)METHOD_FACTORY_MAP.get(request.getMethod());
        if(methodFactory == null)
            throw new IllegalArgumentException((new StringBuilder()).append("Unsupported method: ").append(request.getMethod()).toString());
        HttpRequestBase method = methodFactory.buildMethod(request);
        HttpParams params = new BasicHttpParams();
        HttpClientParams.setRedirecting(params, request.getFollowRedirects());
        HttpConnectionParams.setConnectionTimeout(params, timeoutInMs);
        HttpConnectionParams.setSoTimeout(params, timeoutInMs);
        method.setParams(params);
        boolean sawContentType = false;
        Iterator i$ = request.getHeaderList().iterator();
        do
        {
            if(!i$.hasNext())
                break;
            com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.Header pbHeader = (com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.Header)i$.next();
            if(!pbHeader.getKey().equalsIgnoreCase("Content-Length"))
            {
                method.addHeader(pbHeader.getKey(), pbHeader.getValue());
                if(pbHeader.getKey().equalsIgnoreCase("Content-Type"))
                    sawContentType = true;
            }
        } while(true);
        if(!sawContentType && request.getMethod() == com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest.RequestMethod.POST)
            method.addHeader("Content-Type", "application/x-www-form-urlencoded");
        com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.Builder response = com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.newBuilder();
        try
        {
            HttpResponse httpResponse = doPrivilegedExecute(request, method, response);
            HttpEntity responseEntity = httpResponse.getEntity();
            if(responseEntity != null)
            {
                byte responseBuffer[] = responseToByteArray(responseEntity);
                if(responseBuffer.length > maxResponseLength)
                {
                    byte oldBuffer[] = responseBuffer;
                    responseBuffer = new byte[maxResponseLength];
                    System.arraycopy(oldBuffer, 0, responseBuffer, 0, maxResponseLength);
                    response.setContentWasTruncated(true);
                }
                response.setContent(ByteString.copyFrom(responseBuffer));
            }
            httpclientHeadersToPbHeaders(httpResponse.getAllHeaders(), response);
        }
        catch(SocketTimeoutException ste)
        {
            throw new com.google.apphosting.api.ApiProxy.ApplicationException(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchServiceError.ErrorCode.DEADLINE_EXCEEDED.getNumber(), (new StringBuilder()).append("http method ").append(method.getMethod()).append(" against URL ").append(request.getUrl()).append(" timed out.").toString());
        }
        catch(SSLException e)
        {
            throw new com.google.apphosting.api.ApiProxy.ApplicationException(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchServiceError.ErrorCode.SSL_CERTIFICATE_ERROR.getNumber(), (new StringBuilder()).append("Couldn't validate the server's SSL certificate for URL ").append(request.getUrl()).append(": ").append(e.getMessage()).toString());
        }
        catch(IOException e)
        {
            throw new com.google.apphosting.api.ApiProxy.ApplicationException(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchServiceError.ErrorCode.FETCH_ERROR.getNumber(), (new StringBuilder()).append("Received exception executing http method ").append(method.getMethod()).append(" against URL ").append(request.getUrl()).append(": ").append(e.getMessage()).toString());
        }
        return response.build();
    }

    private HttpResponse doPrivilegedExecute(final com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request, final HttpRequestBase method, final com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.Builder response)
        throws IOException
    {
        try
        {
            return (HttpResponse)AccessController.doPrivileged(new PrivilegedExceptionAction() {

                public HttpResponse run()
                    throws IOException
                {
                    HttpContext context = new BasicHttpContext();
                    HttpResponse httpResponse;
                    if(request.hasMustValidateServerCertificate() && request.getMustValidateServerCertificate())
                        httpResponse = validatingClient.execute(method, context);
                    else
                        httpResponse = nonValidatingClient.execute(method, context);
                    response.setStatusCode(httpResponse.getStatusLine().getStatusCode());
                    HttpHost lastHost = (HttpHost)context.getAttribute("http.target_host");
                    HttpUriRequest lastReq = (HttpUriRequest)context.getAttribute("http.request");
                    String lastUrl = (new StringBuilder()).append(lastHost.toURI()).append(lastReq.getURI()).toString();
                    if(!lastUrl.equals(method.getURI().toString()))
                        response.setFinalUrl(lastUrl);
                    return httpResponse;
                }

            }
);
        }
        catch(PrivilegedActionException e)
        {
            Throwable t = e.getCause();
            if(t instanceof IOException)
                throw (IOException)t;
            else
                throw new RuntimeException(e);
        }
    }

    boolean isAllowedPort(int port)
    {
        return port == -1 || port >= 80 && port <= 90 || port >= 440 && port <= 450 || port >= 1024;
    }

    boolean hasValidURL(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchRequest request)
    {
        if(!request.hasUrl() || request.getUrl().length() == 0)
            return false;
        URL url;
        try
        {
            url = new URL(request.getUrl());
        }
        catch(MalformedURLException e)
        {
            return false;
        }
        if(!url.getProtocol().equals("http") && !url.getProtocol().equals("https"))
            return false;
        if(!isAllowedPort(url.getPort()))
            logger.log(Level.WARNING, String.format("urlfetch received %s ; port %s is not allowed in production!", new Object[] {
                url, Integer.valueOf(url.getPort())
            }));
        return true;
    }

    void httpclientHeadersToPbHeaders(Header headers[], com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.Builder response)
    {
        Map newHeaders = new LinkedHashMap(headers.length);
        Header arr$[] = headers;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            Header header = arr$[i$];
            String name = header.getName();
            String value = (String)newHeaders.get(name);
            if(value == null)
                value = header.getValue();
            else
                value = (new StringBuilder()).append(value).append(", ").append(header.getValue()).toString();
            newHeaders.put(name, value);
        }

        java.util.Map.Entry entry;
        for(Iterator i$ = newHeaders.entrySet().iterator(); i$.hasNext(); response.addHeader(com.google.appengine.api.urlfetch.URLFetchServicePb.URLFetchResponse.Header.newBuilder().setKey((String)entry.getKey()).setValue((String)entry.getValue())))
            entry = (java.util.Map.Entry)i$.next();

    }

    public Double getMaximumDeadline(boolean isOfflineRequest)
    {
        return Double.valueOf(isOfflineRequest ? 600D : 30D);
    }

    private static final int DEFAULT_TIMEOUT_IN_MS = 0x927c0;
    static final int DEFAULT_MAX_RESPONSE_LENGTH = 0x2000000;
    static final int DEFAULT_MAX_REDIRECTS = 5;
    public static final String PACKAGE = "urlfetch";
    private static final int TEMPORARY_RESPONSE_BUFFER_LENGTH = 4096;
    int maxResponseLength;
    int maxRedirects;
    Logger logger;
    private HttpClient validatingClient;
    private HttpClient nonValidatingClient;
    private static final Map METHOD_FACTORY_MAP = buildMethodFactoryMap();
    private int timeoutInMs;
    private static final String TRUST_STORE_LOCATION = "/com/google/appengine/api/urlfetch/dev/cacerts";



}
